<?php
require 'vendor/autoload.php';

use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\SimpleType\TblWidth;

/**
 * 每张照片单独一页（3列：左=中文名，中=对比，右=交付），不展示图片
 *
 * @param string $outputDocx
 * @param array  $deliverPhotoExifs   交付文件列表（你的 $deliverPhotoExifs）
 * @param array  $contrastPhotoExifs  对比文件映射（以 FileName 为键）
 * @param array  $options
 *   - fontName: 默认 'Microsoft YaHei'
 *   - fields  : 关键信息字段映射（键名 => 中文名；顺序即展示顺序）
 *   - onlyExisting: true/false 仅显示“对比或交付任一存在”的字段（默认 true）
 *   - showHeaderRow: true/false 是否在每页表格第一行放“字段/对比/交付”表头（默认 true）
 */
function exportWordPerPhotoThreeCols_NoImage(
    string $outputDocx,
    array $deliverPhotoExifs,
    array $contrastPhotoExifs,
    array $options = []
) {
    // 默认要展示的 EXIF 关键信息（顺序即展示顺序）
    $defaultFields = [
        
        'CUSTOM_REAL_PATH' => "所在文件夹",

        'ExifVersion'          => 'EXIF 版本',

        'FileSize'                 => '文件大小',
        'MimeType'                 => 'MIME类型',

        'DateTime'                 => '最后修改时间',
        'DateTimeOriginal'         => '拍摄时间',
        // 'DateTimeDigitized'        => '数字化时间',

        // 'Make'                     => '厂商',
        'Model'                    => '相机型号',
        'UndefinedTag:0xA431'      => '机身序列号',
        'UndefinedTag:0xA434'      => '镜头型号',
        'UndefinedTag:0xA435'      => '镜头序列号',

        'ExposureTime'             => '快门',
        'FNumber'                  => '光圈',
        'ISOSpeedRatings'          => 'ISO',
        'UndefinedTag:0x8830'      => '感光度类型',
        'UndefinedTag:0x8832'      => '推荐曝光指数',

        'ExposureProgram'          => '曝光程序',
        'ExposureMode'             => '曝光模式',
        'ExposureBiasValue'        => '曝光补偿',
        'MeteringMode'             => '测光模式',
        'Flash'                    => '闪光灯',
        'WhiteBalance'             => '白平衡',

        'FocalLength'              => '焦距',
        'ApertureValue'            => '光圈值(Av)',
        'MaxApertureValue'         => '最大光圈',
        'ShutterSpeedValue'        => '快门值(Tv)',

        'ColorSpace'               => '色彩空间',
        'Software'                 => '软件',

        'XResolution'              => 'X分辨率',
        'YResolution'              => 'Y分辨率',
        'ResolutionUnit'           => '分辨率单位',
        'FocalPlaneXResolution'    => '像面X分辨率',
        'FocalPlaneYResolution'    => '像面Y分辨率',
        'FocalPlaneResolutionUnit' => '像面分辨率单位'
    ];

    $fields        = $options['fields']        ?? $defaultFields;
    $onlyExisting  = $options['onlyExisting']  ?? true;
    $showHeaderRow = $options['showHeaderRow'] ?? true;
    $fontName      = $options['fontName']      ?? 'Microsoft YaHei';
    $fontSize      = $options['fontSize']      ?? 10;
    $paraTight = ['spaceBefore'=>0, 'spaceAfter'=>0, 'lineHeight'=>0.8];

    $phpWord = new PhpWord();
    $phpWord->setDefaultFontName($fontName);
    $phpWord->setDefaultFontSize($fontSize);


    foreach ($deliverPhotoExifs as $d) {
        $fileName = $d['FileName'] ?? '(未命名)';
        $c = $contrastPhotoExifs[$fileName] ?? [];

        // 一页
        $section = $phpWord->addSection([
            'orientation' => 'portrait',
            'marginLeft'  => 800, 'marginRight' => 800,
            'marginTop'   => 800, 'marginBottom'=> 800,
        ]);

        // 页标题（文件名）
        $section->addText($fileName, ['bold'=>true,'size'=>$fontSize+3],$paraTight);
        $section->addTextBreak(1);

        // 三列表格：左 20% | 中 40% | 右 40%
        $table = $section->addTable([
            'width'      => 100 * 50,
            'unit'       => TblWidth::PERCENT,
            'borderSize' => 6,
            'borderColor'=> 'cccccc',
            'cellMargin' => 80,
        ]);

        // 可选表头行
        if ($showHeaderRow) {
            $table->addRow();
            $table->addCell(20 * 50, ['bgColor'=>'F4F4F4'])->addText('字段', ['bold'=>true],$paraTight);
            $table->addCell(40 * 50, ['bgColor'=>'F4F4F4'])->addText('对比', ['bold'=>true],$paraTight);
            $table->addCell(40 * 50, ['bgColor'=>'F4F4F4'])->addText('交付', ['bold'=>true],$paraTight);
        }

        // EXIF 行（左列中文名，中列=对比值，右列=交付值）
        foreach ($fields as $key => $label) {
            $vc = formatExifValuePretty($key, $c);
            $vd = formatExifValuePretty($key, $d);

            if ($onlyExisting && $vc === '-' && $vd === '-') {
                continue; // 两边都没有就不显示该行
            }

            $table->addRow();
            $table->addCell(20 * 50, ['bgColor'=>'F9F9F9'])->addText($label, ['bold'=>true],$paraTight);
            $table->addCell(40 * 50)->addText($vc,$paraTight);
            $table->addCell(40 * 50)->addText($vd,$paraTight);
        }
    }

    IOFactory::createWriter($phpWord, 'Word2007')->save($outputDocx);
}

/** 将 EXIF 值做轻量可读化（时间原样；分数等转可读；枚举映射） */
function formatExifValuePretty(string $key, array $exif): string {
    // 直接取值；若没有则尝试嵌套键（如 COMPUTED.ApertureFNumber）
    $v = $exif[$key] ?? null;
    if ($v === null) {
        $nestedMap = [
            'ApertureFNumber' => 'COMPUTED.ApertureFNumber',
        ];
        if (isset($nestedMap[$key])) {
            $vn = getNested($exif, $nestedMap[$key]);
            return $vn !== null ? (string)$vn : '-';
        }
        return '-';
    }

    // 基础类型
    if (is_string($v) || is_numeric($v)) {
        //文件夹获取
        if ($key === 'CUSTOM_REAL_PATH') {
            return basename(dirname($v));
        }
        // 文件大小：字节 + 可读
        if ($key === 'FileSize') {
            return number_format((int)$v) . ' (' . humanSize((int)$v) . ')';
        }
        // 光圈：FNumber "4/1" → "f/4.0"
        if ($key === 'FNumber' && is_string($v) && strpos($v, '/') !== false) {
            $f = rationalToFloat($v);
            return $f !== null ? ('f/' . trimRightZeros(number_format($f, 1))) : (string)$v;
        }
        // 焦距："92/1" → "92mm"
        if ($key === 'FocalLength' && is_string($v) && strpos($v, '/') !== false) {
            $f = rationalToFloat($v);
            return $f !== null ? (trimRightZeros(number_format($f, 2)) . 'mm') : (string)$v;
        }
        // 曝光补偿："0/1" → "0"
        if ($key === 'ExposureBiasValue' && is_string($v) && strpos($v, '/') !== false) {
            $f = rationalToFloat($v);
            return $f !== null ? (string)$f : (string)$v;
        }

        // —— 枚举映射 ——（其余值按原样）
        if ($key === 'ResolutionUnit')           return mapResolutionUnit((int)$v);
        if ($key === 'FocalPlaneResolutionUnit') return mapResolutionUnit((int)$v);
        if ($key === 'ExposureProgram')          return mapExposureProgram((int)$v);
        if ($key === 'ExposureMode')             return mapExposureMode((int)$v);
        if ($key === 'MeteringMode')             return mapMeteringMode((int)$v);
        if ($key === 'WhiteBalance')             return mapWhiteBalance((int)$v);
        if ($key === 'Flash')                    return mapFlash((int)$v);
        if ($key === 'ColorSpace')               return mapColorSpace((int)$v);

        // 时间、字符串等：原样
        return (string)$v;
    }

    // 数组/对象：转 JSON
    if (is_array($v) || is_object($v)) {
        return json_encode($v, JSON_UNESCAPED_UNICODE);
    }

    return (string)$v;
}

/** 工具：读取嵌套键 path 如 "COMPUTED.ApertureFNumber" */
function getNested(array $arr, string $path) {
    $cur = $arr;
    foreach (explode('.', $path) as $p) {
        if (!is_array($cur) || !array_key_exists($p, $cur)) return null;
        $cur = $cur[$p];
    }
    return $cur;
}

/** 分数字符串 "a/b" → float */
function rationalToFloat(string $r): ?float {
    if (strpos($r, '/') === false) return null;
    [$num, $den] = array_map('floatval', explode('/', $r, 2));
    if ($den == 0.0) return null;
    return $num / $den;
}

/** 字节 → 人类可读 */
function humanSize(int $bytes): string {
    $u = ['B','KB','MB','GB','TB'];
    $i = 0;
    while ($bytes >= 1024 && $i < count($u) - 1) {
        $bytes /= 1024;
        $i++;
    }
    return sprintf('%.2f %s', $bytes, $u[$i]);
}

/** 去掉小数右侧多余 0 与点号 */
function trimRightZeros(string $s): string {
    return rtrim(rtrim($s, '0'), '.');
}

/* =========================
 *   枚举映射（map* 系列）
 * ========================= */

/** 分辨率单位：1=无/不指定, 2=英寸, 3=厘米 */
function mapResolutionUnit(int $v): string {
    $map = [
        1 => '无',
        2 => '英寸',
        3 => '厘米',
    ];
    return $map[$v] ?? ('未知(' . $v . ')');
}

/** 曝光程序（EXIF ExposureProgram） */
function mapExposureProgram(int $v): string {
    $map = [
        0 => '未定义',
        1 => '手动',
        2 => '程序自动 (Program AE)',
        3 => '光圈优先 (A/Av)',
        4 => '快门优先 (S/Tv)',
        5 => '景深优先 (Creative)',
        6 => '速度优先 (Action)',
        7 => '人像',
        8 => '风景',
    ];
    return $map[$v] ?? ('其他(' . $v . ')');
}

/** 曝光模式（EXIF ExposureMode） */
function mapExposureMode(int $v): string {
    $map = [
        0 => '自动曝光',
        1 => '手动曝光',
        2 => '自动包围曝光 (AEB)',
    ];
    return $map[$v] ?? ('其他(' . $v . ')');
}

/** 测光模式（EXIF MeteringMode） */
function mapMeteringMode(int $v): string {
    $map = [
        0   => '未知',
        1   => '平均',
        2   => '中央重点平均',
        3   => '点测光',
        4   => '多点测光',
        5   => '矩阵/评价测光',
        6   => '局部测光',
        255 => '其他',
    ];
    return $map[$v] ?? ('其他(' . $v . ')');
}

/**
 * 白平衡（EXIF WhiteBalance）
 * 注：不同厂商/工具可能有差异；这里使用 1=自动, 2=手动 的常见映射。
 */
function mapWhiteBalance(int $v): string {
    $map = [
        0 => '自动',
        1 => '自动',
        2 => '手动',
    ];
    return $map[$v] ?? ('其他(' . $v . ')');
}

/** 色彩空间（EXIF ColorSpace） */
function mapColorSpace(int $v): string {
    $map = [
        1      => 'sRGB',
        2      => 'Adobe RGB',
        65535  => '未校准 (Uncalibrated)',
    ];
    return $map[$v] ?? ('其他(' . $v . ')');
}

/**
 * 闪光灯（EXIF Flash，位掩码解析）
 * 参考位：
 *  bit0: 是否触发
 *  bit1-2: 回光检测 (00 未知/不适用, 10 未检测, 11 检测到)
 *  bit3-4: 模式 (01 强制开, 10 强制关, 11 自动)
 *  bit5: 无闪光功能
 *  bit6: 红眼消除
 */
function mapFlash(int $v): string {
    $parts = [];

    $fired = ($v & 0x1) ? '触发' : '未触发';
    $parts[] = '闪光' . $fired;

    // 回光
    $ret = ($v >> 1) & 0x3;
    if ($ret === 2)       $parts[] = '回光未检测';
    elseif ($ret === 3)   $parts[] = '回光检测到';

    // 模式
    $mode = ($v >> 3) & 0x3;
    if ($mode === 1)      $parts[] = '强制开';
    elseif ($mode === 2)  $parts[] = '强制关';
    elseif ($mode === 3)  $parts[] = '自动';

    if ($v & 0x20)        $parts[] = '无闪光功能';
    if ($v & 0x40)        $parts[] = '防红眼';

    return $parts ? implode('，', $parts) . " (0x" . dechex($v) . ")" : (string)$v;
}

//获取图片的exif信息
function getPhotoExif($photoPath){
    if (preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $photoPath)) {
        $exif = @exif_read_data($photoPath);
        if (!empty($exif['DateTime'])) {
            $exif["CUSTOM_REAL_PATH"] = $photoPath;
            return $exif;
        }
    }
    return [];
}
//获取所有图片的EXIF信息
function getPhotoExifs($photoPaths){
    $exifs = [];
    foreach ($photoPaths as $key => $photoPath) {
        $exif = getPhotoExif($photoPath);
        if (!empty($exif)) {
            $exifs[] = $exif;
        }   
    }
    return $exifs;
}

//获取照片文件夹基础目录
$baseDir = dirname(__FILE__,2).DIRECTORY_SEPARATOR."照片".DIRECTORY_SEPARATOR;
$contrastPhotoDir = $baseDir."对照".DIRECTORY_SEPARATOR;
$deliverPhotoDir = $baseDir."交付".DIRECTORY_SEPARATOR;
//文件夹是否存在
if (!is_dir($contrastPhotoDir)) exit("对照照片文件夹不存在");
if (!is_dir($deliverPhotoDir)) exit("交付照片文件夹不存在");
//获取对照文件夹中的多个对比文件夹
$contrastPhotoDirs = glob($contrastPhotoDir."*",GLOB_ONLYDIR);
if (empty($contrastPhotoDirs)) exit("对照照片文件夹不存在");
//获取交付照片的exif信息
$deliverPhotoPaths = glob($deliverPhotoDir."*");
if (empty($deliverPhotoPaths)) exit("交付照片文件夹不能为空");
$deliverPhotoExifs = getPhotoExifs($deliverPhotoPaths);
//对交付照片的exif信息按照DateTime进行排序
usort($deliverPhotoExifs, function($a, $b) {
    $aTimeStamp = strtotime($a['DateTime']??"");
    $bTimeStamp = strtotime($b['DateTime']??"");
    if ( $aTimeStamp == $bTimeStamp) return 0;
    return ($aTimeStamp < $bTimeStamp) ? -1 : 1;
});
//获取对比照片的EXIF信息
$contrastPhotoExifs = array_reduce($deliverPhotoExifs, function($carry,$deliverPhotoExif)use($contrastPhotoDirs){
    $fileName = $deliverPhotoExif['FileName']??"";
    foreach($contrastPhotoDirs as $contrastPhotoDir){
        $contrastPhotoPath = $contrastPhotoDir.DIRECTORY_SEPARATOR.$fileName;
        if (is_file($contrastPhotoPath) && !empty($exif = getPhotoExif($contrastPhotoPath))) {
            $carry[$fileName] = $exif;
        }
    }
    return $carry;
},[]);


exportWordPerPhotoThreeCols_NoImage(
    __DIR__.DIRECTORY_SEPARATOR.date("YmdHis")."照片详细EXIF对比.docx",
    $deliverPhotoExifs,
    $contrastPhotoExifs,
    [
        'fontName'      => 'Microsoft YaHei',
        'onlyExisting'  => true,   // 两边都没有的字段不显示
        'showHeaderRow' => true,   // 每页表格第一行显示“字段/对比/交付”
        // 'fields' => [...自定义字段顺序/中文名...], // 如需覆盖默认字段
    ]
);

echo "Word 导出完成\n";

